package uk.ac.tees.aetoolkit;

import java.util.ArrayList;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.speech.RecognizerIntent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

/**
 * Calculator class used for the calculator application in the AEToolkit with
 * the ability to function through voice control or manual user input. It has a
 * realistic style which makes the application look like a real calculator.
 * 
 * @author Sohail Rahman, Mark Williamson, Robert Sheffield.
 * 
 */
public class Calculator extends Activity implements OnTouchListener {

	/**
	 * String used to hold the users input on the calculator
	 */
	private String in = "";
	/**
	 * TextView used as a display for the calculator.
	 */
	private TextView display;
	/**
	 * String object used to store the calculations operator.
	 */
	private String operator = "";

	/**
	 * Variables for the 1st and 2nd number entered by user.
	 */
	double num1;
	double num2;

	/**
	 * String variable used to hold what the user says for voice use.
	 */
	private String speech = "";

	/**
	 * Called when the activity is first created.
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.layout_calculator);
		LinearLayout layMain = (LinearLayout) findViewById(R.id.linear_id);
		// Set an OnTouchListener on to the layout of this calculator.
		layMain.setOnTouchListener((OnTouchListener) this);
		display = (TextView) findViewById(R.id.textView1);
		
		ImageButton calcHelp = (ImageButton) findViewById(R.id.imageButton1);
		calcHelp.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				AlertDialog alertDialog;
				AlertDialog.Builder alertDialog2 = new AlertDialog.Builder(
						Calculator.this);
				alertDialog2.setTitle("Help");
				alertDialog2
						.setMessage("Touchscreen use\n\nClick on the buttons to do a calculation, there is a square root function, a percentage function, and the usual operators.\n\nVoice Recognition use\n\n To use voice recognition click on the speech button, once the chime as sounded, speak into the microphone the calculation you wish to carry out, if the calculation is valid the answer will appear in the calculator screen. A valid calculation is in the format of one times fifteen.");
				alertDialog2.show();

			}
		});
		
	}

	/**
	 * Method used for when the user makes a selection on the view.
	 */
	public boolean onTouch(View v, MotionEvent event) {
		double x = getXposition(event);
		double y = getYposition(event);
		// If user clicks on a calculator button then handle it.
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			// Handle what happens when user clicks C,0,.,+/- or =
			if ((y > 69) && (y < 75)) {
				if ((x > 9.5) && (x < 20)) {
					// Clear everything.
					in = "";
					operator = "";
				} else if ((x > 24.5) && (x < 34.5)) {
					in = in.concat("0");
				} else if ((x > 38.5) && (x < 48.5)) {
					in = in.concat(".");
				} else if ((x > 51.7) && (x < 61.7)) {
					if ((!in.toString().startsWith("-"))
							&& (!in.toString().startsWith("+"))) {
						in = "-" + in.toString();
					} else if (in.toString().startsWith("-")) {
						in = in.replace("-", "+");
					} else if (in.toString().startsWith("+")) {
						in = in.replace("+", "-");
					}
				} else if ((x > 80) && (x < 90)) {
					num2 = Double.parseDouble(in.substring(1, in.length()));
					in = "" + calculate(num1, num2, operator);
				}
			}
			// Handle when numbers 1, 2, 3, -, 'voice' are clicked on.
			if ((y > 60) && (y < 67)) {
				if ((x > 25) && (x < 34.5)) {
					in = in.concat("1");
				} else if ((x > 38) && (x < 48)) {
					in = in.concat("2");
				} else if ((x > 52) && (x < 61.5)) {
					in = in.concat("3");
				} else if ((x > 10) && (x < 20)) {
					int RESULT_SPEECH = 1;
					// creates intent for voice commands
					Intent intent = new Intent(
							RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
					intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
							"en-UK");
					try {
						// starts activity for speech.
						startActivityForResult(intent, RESULT_SPEECH);
						speech = "";
					} catch (ActivityNotFoundException a) {
						// exception in case device does not support voice.
						Toast.makeText(getApplicationContext(),
								"Your device doesn't support Speech to Text",
								Toast.LENGTH_SHORT).show();
					}
				} else if ((x > 80) && (x < 90)) {
					operator = "-";
					num1 = Double.parseDouble(in);
					in = "- ";
				}
			}
			// Handle what happens when numbers 4, 5, 6, x, / are clicked on.
			if ((y > 52.5) && (y < 58.5)) {
				if ((x > 25) && (x < 35)) {
					in = in.concat("4");
				} else if ((x > 38.5) && (x < 48)) {
					in = in.concat("5");
				} else if ((x > 52) && (x < 62)) {
					in = in.concat("6");
				} else if ((x > 66) && (x < 76)) {
					operator = "*";
					num1 = Double.parseDouble(in);
					in = "x ";
				} else if ((x > 79.5) && (x < 90)) {
					operator = "/";
					num1 = Double.parseDouble(in);
					in = "\u00f7";
				}
			}
			// Handle when numbers 7, 8, 9, %, or square root are clicked on
			if ((y > 43) && (y < 50)) {
				if ((x > 25) && (x < 35)) {
					in = in.concat("7");
				} else if ((x > 38.5) && (x < 48.5)) {
					in = in.concat("8");
				} else if ((x > 52) && (x < 61.5)) {
					in = in.concat("9");
				} else if ((x > 66.5) && (x < 76.5)) {
					in = in.concat("%");
				} else if ((x > 80) && (x < 90)) {
					operator = "%";
					num1 = Double.parseDouble(in);
					in = "% ";
				}
			}
			// Handle what happens when the + operator is clicked on.
			if ((y > 60.5) && (y < 75.5)) {
				if ((x > 66) && (x < 76)) {
					operator = "+";
					num1 = Double.parseDouble(in);
					in = "+ ";
				}
			}
		}
		display.setText(in);
		return true;
	}

	/**
	 * Method for getting the click position on the X axis.
	 * 
	 * @param event is the type of MotionEvent.
	 * @return 'x' is the position on the x axis.
	 */
	public double getXposition(MotionEvent event) {
		double windowWidth = getWindow().getDecorView().getWidth();
		float xDensity = event.getX();
		double x = (xDensity / windowWidth) * 100;
		return x;
	}

	/**
	 * Method for getting the click position on the Y axis.
	 * 
	 * @param event is the MotionEvent type.
	 * @return 'y' is the position on the y axis.
	 */
	public double getYposition(MotionEvent event) {
		double windowHeight = getWindow().getDecorView().getHeight();
		float yDensity = event.getY();
		double y = (yDensity / windowHeight) * 100;
		return y;
	}

	/**
	 * Method used to perform calculations based on user selections.
	 * 
	 * @param num1 is the first number passed in.
	 * @param num2 is the second number passed in.
	 * @param op is the operator chosen by the user
	 * @return result - the result of the calculation.
	 */
	public double calculate(double num1, double num2, String op) {
		double result = 0;
		if (op.equals("-")) {
			result = num1 - num2;
		} else if (op.equals("+")) {
			result = num1 + num2;
		} else if (op.equals("/")) {
			result = num1 / num2;
		} else if (op.equals("*")) {
			result = num1 * num2;
		}
		return result;
	}

	/**
	 * Method used to handle calculations set by the users voice.
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (resultCode == RESULT_OK && null != data) {
			// ArrayList containing voice text from user.
			ArrayList<String> text = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
			speech = text.get(0);
			String operator = "";
			String[] operation;
			// Flag to check if user has said command correctly.
			boolean flag = false;
			// Finds the operator and the two numbers to perform calculation.
			try {
				if (speech.contains("plus")) {
					operation = speech.split("plus");
					operator = "+";
					num1 = Double.parseDouble(operation[0]);
					num2 = Double.parseDouble(operation[1]);
					flag = true;
				} else if (speech.contains("minus")) {
					operation = speech.split("minus");
					operator = "-";
					num1 = Double.parseDouble(operation[0]);
					num2 = Double.parseDouble(operation[1]);
					flag = true;
				} else if (speech.contains("times")) {
					operation = speech.split("times");
					operator = "*";
					num1 = Double.parseDouble(operation[0]);
					num2 = Double.parseDouble(operation[1]);
					flag = true;
				} else if (speech.contains("divided")) {
					operation = speech.split("divided");
					operator = "/";
					num1 = Double.parseDouble(operation[0]);
					num2 = Double.parseDouble(operation[1]);
					flag = true;
				}
				if (flag == true) {
					// Sets calculators display to the result of the calculation.
					display.setText("" + calculate(num1, num2, operator));
				} else {
					Toast.makeText(this,"Say calculation in format: ## + ##",
							Toast.LENGTH_SHORT).show();
				}				
			} catch(Exception e){
				Toast.makeText(this, "Unfortunately I didn't understand that!", Toast.LENGTH_SHORT).show();
			}
		}
	}
	
}
